package common

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"math"
	"strconv"
)

// ToString 任意类型转字符串
func ToString(v interface{}) string {
	if v == nil {
		return ""
	}
	switch result := v.(type) {
	case string:
		return result
	case []byte:
		return string(result)
	default:
		return fmt.Sprint(result)
	}
}

// ToInt 任意类型转int
func ToInt(val interface{}) int {
	switch val.(type) {
	case float64:
		return int(val.(float64))
	case int32:
		return int(val.(int32))
	case int:
		return val.(int)
	case int64:
		return int(val.(int64))
	case string:
		return ParseInt(val.(string), 0)
	}
	return 0
}

// ToInt64 任意类型转int64
func ToInt64(val interface{}) int64 {
	switch val.(type) {
	case float64:
		return int64(val.(float64))
	case int:
		return int64(val.(int))
	case int32:
		return int64(val.(int32))
	case int64:
		return val.(int64)
	case string:
		return ParseInt64String(val.(string))
	}
	return 0
}

// ParseInt string转成int
func ParseInt(b string, defInt int) int {
	id, err := strconv.Atoi(b)
	if err != nil {
		return defInt
	}
	return id
}

// ParseInt64String string转成int64
func ParseInt64String(b string) int64 {
	id, _ := strconv.ParseInt(b, 10, 64)
	return id
}

// InterfaceToStr 任意类型转string
func InterfaceToStr(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

// ToFloat64 任意类型转float64
func ToFloat64(value interface{}) float64 {
	num, err := strconv.ParseFloat(ToString(value), 64)
	if err != nil {
		return 0
	}
	return num
}

// ParseByteInt64 ...
func ParseByteInt64(byteData []byte) int64 {
	if len(byteData) < 8 {
		return 0
	}
	buf := bytes.NewBuffer(byteData)
	var i2 int64
	binary.Read(buf, binary.BigEndian, &i2)
	return i2
}

// ParseByteInt32 ...
func ParseByteInt32(byteData []byte) int32 {
	if len(byteData) < 4 {
		return 0
	}
	buf := bytes.NewBuffer(byteData)
	var i2 int32
	binary.Read(buf, binary.BigEndian, &i2)
	return i2
}

// ParseByteFloat64 ...
func ParseByteFloat64(byteData []byte) float64 {
	if len(byteData) < 8 {
		return 0
	}
	bits := binary.BigEndian.Uint64(byteData)
	result := math.Float64frombits(bits)
	if math.IsNaN(result) {
		return 0
	} else if math.IsInf(result, 0) {
		return 0
	}
	return result
}

// ParseByteFloat32 ...
func ParseByteFloat32(byteData []byte) float32 {
	if len(byteData) < 4 {
		return 0
	}
	bits := binary.BigEndian.Uint32(byteData)
	return math.Float32frombits(bits)
}
